﻿using SD.Common.PoweredByLee;
using SD.ContentSystem.AppService.Maps;
using SD.ContentSystem.Domain.Entities;
using SD.ContentSystem.Domain.IRepositories;
using SD.ContentSystem.Domain.Mediators;
using SD.ContentSystem.IAppService.DTOs.Outputs;
using SD.ContentSystem.IAppService.Interfaces;
using SD.Infrastructure.DTOBase;
using SD.Infrastructure.Global.Transaction;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;

namespace SD.ContentSystem.AppService.Implements
{
    /// <summary>
    /// 文章服务契约实现
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class ArticleContract : IArticleContract
    {
        #region # 字段及依赖注入构造器

        /// <summary>
        /// 领域服务中介者
        /// </summary>
        private readonly DomainServiceMediator _svcMediator;

        /// <summary>
        /// 仓储中介者
        /// </summary>
        private readonly RepositoryMediator _repMediator;

        /// <summary>
        /// 单元事务
        /// </summary>
        private readonly IUnitOfWorkCMS _unitOfWork;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        /// <param name="svcMediator">领域服务中介者</param>
        /// <param name="repMediator">仓储中介者</param>
        /// <param name="unitOfWork">单元事务</param>
        public ArticleContract(DomainServiceMediator svcMediator, RepositoryMediator repMediator,
            IUnitOfWorkCMS unitOfWork)
        {
            this._svcMediator = svcMediator;
            this._repMediator = repMediator;
            this._unitOfWork = unitOfWork;
        }

        #endregion


        //命令部分

        #region # 创建文章 —— void CreateArticle(Guid channelId, string title, string subTitle...
        /// <summary>
        /// 创建文章
        /// </summary>
        /// <param name="channelNo">栏目编号</param>
        /// <param name="title">标题</param>
        /// <param name="subTitle">副标题</param>
        /// <param name="author">作者</param>
        /// <param name="source">来源</param>
        /// <param name="content">内容</param>
        /// <param name="imagePath">图片地址</param>
        /// <param name="thumbPath">缩略图</param>
        /// <param name="attachmentPath">附件</param>
        /// <param name="sort">排序</param>
        /// <param name="isTop">是否置顶</param>
        public void CreateArticle(string channelNo, string title, string subTitle, string author, string source,
            string content, string imagePath, string thumbPath, string attachmentPath, int sort, bool isTop)
        {
            Article article = new Article(channelNo, title, subTitle, author, source, content, imagePath, thumbPath,
                attachmentPath, sort, isTop);

            Channel currentChannel = this._repMediator.ChannelRep.Single(channelNo);
            string url = string.Format("{0}{1}{2}", currentChannel.StoragePath, article.StoragePath, article.FileName);
            article.SetUrl(url);

            this._unitOfWork.RegisterAdd(article);
            this._unitOfWork.UnitedCommit();
        }
        #endregion

        #region # 修改文章 —— void UpdateArticle(Guid articleId, string loginId...
        /// <summary>
        /// 修改文章
        /// </summary>
        /// <param name="articleId">文章Id</param>
        /// <param name="title">标题</param>
        /// <param name="subTitle">副标题</param>
        /// <param name="author">作者</param>
        /// <param name="source">来源</param>
        /// <param name="content">内容</param>
        /// <param name="imagePath">图片地址</param>
        /// <param name="thumbPath">缩略图</param>
        /// <param name="attachmentPath">附件</param>
        /// <param name="sort">排序</param>
        public void UpdateArticle(Guid articleId, string title, string subTitle, string author, string source,
            string content, string imagePath, string thumbPath, string attachmentPath, int sort)
        {
            Article currentArticle = this._unitOfWork.Resolve<Article>(articleId);

            currentArticle.UpdateInfo(title, subTitle, author, source, content, imagePath, thumbPath, attachmentPath,
                sort);

            Channel currentChannel = this._repMediator.ChannelRep.Single(currentArticle.ChannelNo);
            string url = string.Format("{0}{1}{2}", currentChannel.StoragePath, currentArticle.StoragePath, currentArticle.FileName);
            currentArticle.SetUrl(url);

            this._unitOfWork.RegisterSave(currentArticle);
            this._unitOfWork.UnitedCommit();
        }
        #endregion

        #region # 设置上一篇与下一篇 —— void SetPrevAndNextPage(Guid articleId...
        /// <summary>
        /// 设置上一篇与下一篇
        /// </summary>
        /// <param name="articleId">文章Id</param>
        /// <param name="prevPage">上一篇</param>
        /// <param name="nextPage">下一篇</param>
        public void SetPrevAndNextPage(Guid articleId, string prevPage, string nextPage)
        {
            Article currentArticle = this._unitOfWork.Resolve<Article>(articleId);
            currentArticle.SetPrevAndNextPage(prevPage, nextPage);

            this._unitOfWork.RegisterSave(currentArticle);
            this._unitOfWork.UnitedCommit();
        }
        #endregion

        #region # 置顶文章 —— void SetArticleTop(Guid articleId)
        /// <summary>
        /// 置顶文章
        /// </summary>
        /// <param name="articleId">文章Id</param>
        public void SetArticleTop(Guid articleId)
        {
            Article currentArticle = this._unitOfWork.Resolve<Article>(articleId);
            currentArticle.SetTop();

            this._unitOfWork.RegisterSave(currentArticle);
            this._unitOfWork.UnitedCommit();
        }
        #endregion

        #region # 取消置顶文章 —— void CancelArticleTop(Guid articleId)
        /// <summary>
        /// 取消置顶文章
        /// </summary>
        /// <param name="articleId">文章Id</param>
        public void CancelArticleTop(Guid articleId)
        {
            Article currentArticle = this._unitOfWork.Resolve<Article>(articleId);
            currentArticle.CancelTop();

            this._unitOfWork.RegisterSave(currentArticle);
            this._unitOfWork.UnitedCommit();
        }
        #endregion

        #region # 发布文章 —— void PublishArticle(Guid articleId)
        /// <summary>
        /// 发布文章
        /// </summary>
        /// <param name="articleId">文章Id</param>
        public void PublishArticle(Guid articleId)
        {
            Article currentArticle = this._unitOfWork.Resolve<Article>(articleId);
            currentArticle.Publish();

            this._unitOfWork.RegisterSave(currentArticle);
            this._unitOfWork.UnitedCommit();
        }
        #endregion

        #region # 删除文章 —— void RemoveArticle(Guid articleId)
        /// <summary>
        /// 删除文章
        /// </summary>
        /// <param name="articleId">文章Id</param>
        public void RemoveArticle(Guid articleId)
        {
            this._unitOfWork.RegisterPhysicsRemove<Article>(articleId);
            this._unitOfWork.UnitedCommit();
        }
        #endregion


        #region # 创建栏目 —— void CreateChannel(string channelNo, string channelName...
        /// <summary>
        /// 创建栏目
        /// </summary>
        /// <param name="channelNo">栏目编号</param>
        /// <param name="channelName">栏目名称</param>
        /// <param name="storagePath">保存路径</param>
        /// <param name="indexTemplatePath">聚合页模板路径</param>
        /// <param name="listTemplatePath">列表页模板路径</param>
        /// <param name="detailTemplatePath">明细页模板路径</param>
        /// <param name="pageSize">页容量</param>
        /// <param name="sort">排序</param>
        /// <param name="isNavigator">是否是导航</param>
        /// <param name="description">描述</param>
        /// <param name="parentChannelId">上级栏目Id</param>
        public void CreateChannel(string channelNo, string channelName, string storagePath, string indexTemplatePath, string listTemplatePath, string detailTemplatePath, int pageSize, int sort, bool isNavigator, string description, Guid? parentChannelId)
        {
            //验证
            Assert.IsFalse(this._repMediator.ChannelRep.Exists(channelNo), "栏目编号已存在！");

            Channel parentChannel = parentChannelId == null
                ? null
                : this._unitOfWork.Resolve<Channel>(parentChannelId.Value);

            Channel channel = new Channel(channelNo, channelName, storagePath, indexTemplatePath, listTemplatePath, detailTemplatePath, pageSize, sort, isNavigator, description, parentChannel);

            this._unitOfWork.RegisterAdd(channel);
            this._unitOfWork.UnitedCommit();
        }
        #endregion

        #region # 修改栏目 —— void UpdateChannel(Guid channelId, string channelName, string storagePath...
        /// <summary>
        /// 修改栏目
        /// </summary>
        /// <param name="channelId">栏目Id</param>
        /// <param name="channelName">栏目名称</param>
        /// <param name="storagePath">保存路径</param>
        /// <param name="indexTemplatePath">聚合页模板路径</param>
        /// <param name="listTemplatePath">列表页模板路径</param>
        /// <param name="detailTemplatePath">明细页模板路径</param>
        /// <param name="pageSize">页容量</param>
        /// <param name="sort">排序</param>
        /// <param name="isNavigator">是否是导航</param>
        /// <param name="description">描述</param>
        public void UpdateChannel(Guid channelId, string channelName, string storagePath, string indexTemplatePath, string listTemplatePath, string detailTemplatePath, int pageSize, int sort, bool isNavigator, string description)
        {
            Channel currentChannel = this._unitOfWork.Resolve<Channel>(channelId);
            currentChannel.UpdateInfo(channelName, storagePath, indexTemplatePath, listTemplatePath, detailTemplatePath, pageSize, sort, isNavigator, description);

            this._unitOfWork.RegisterSave(currentChannel);
            this._unitOfWork.UnitedCommit();
        }
        #endregion

        #region # 删除栏目 —— void RemoveChannel(Guid channelId)
        /// <summary>
        /// 删除栏目
        /// </summary>
        /// <param name="channelId">栏目Id</param>
        public void RemoveChannel(Guid channelId)
        {
            //递归删除
            Channel currentChannel = this._unitOfWork.Resolve<Channel>(channelId);

            //验证
            Assert.IsFalse(this._repMediator.ArticleRep.ExistsByChannel(currentChannel.Number), "栏目下存在文章，不可删除！");

            foreach (Channel subMenu in currentChannel.SubNodes.ToArray())
            {
                this.RemoveChannel(subMenu.Id);
            }

            this._unitOfWork.RegisterPhysicsRemove<Channel>(currentChannel);
            this._unitOfWork.UnitedCommit();
        }
        #endregion


        //查询部分

        #region # 获取文章 —— ArticleInfo GetArticle(Guid articleId)
        /// <summary>
        /// 获取文章
        /// </summary>
        /// <param name="articleId">文章Id</param>
        /// <returns>文章</returns>
        public ArticleInfo GetArticle(Guid articleId)
        {
            Article currentArticle = this._repMediator.ArticleRep.Single(articleId);

            IDictionary<string, ChannelInfo> channelInfos = this._repMediator.ChannelRep.Find(new[] { currentArticle.ChannelNo }).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            return currentArticle.ToDTO(channelInfos);
        }
        #endregion

        #region # 获取上一篇文章 —— ArticleInfo GetPrevArticle(Guid articleId...
        /// <summary>
        /// 获取上一篇文章
        /// </summary>
        /// <param name="articleId">文章Id</param>
        /// <param name="channelNo">栏目编号</param>
        /// <returns>文章</returns>
        public ArticleInfo GetPrevArticle(Guid articleId, string channelNo)
        {
            Article prevArticle = this._repMediator.ArticleRep.GetPrevArticle(channelNo, articleId);

            IDictionary<string, ChannelInfo> channelInfos = this._repMediator.ChannelRep.Find(new[] { prevArticle.ChannelNo }).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            return prevArticle.ToDTO(channelInfos);
        }
        #endregion

        #region # 获取下一篇文章 —— ArticleInfo GetNextArticle(Guid articleId...
        /// <summary>
        /// 获取下一篇文章
        /// </summary>
        /// <param name="articleId">文章Id</param>
        /// <param name="channelNo">栏目编号</param>
        /// <returns>文章</returns>
        public ArticleInfo GetNextArticle(Guid articleId, string channelNo)
        {
            Article nextArticle = this._repMediator.ArticleRep.GetNextArticle(channelNo, articleId);

            IDictionary<string, ChannelInfo> channelInfos = this._repMediator.ChannelRep.Find(new[] { nextArticle.ChannelNo }).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            return nextArticle.ToDTO(channelInfos);
        }
        #endregion

        #region # 获取所有文章列表 —— IEnumerable<ArticleInfo> GetArticles()
        /// <summary>
        /// 获取所有文章列表
        /// </summary>
        /// <returns>文章列表</returns>
        public IEnumerable<ArticleInfo> GetArticles()
        {
            IEnumerable<Article> articles = this._repMediator.ArticleRep.FindAll().ToArray();

            IEnumerable<string> channelNos = articles.Select(x => x.ChannelNo);
            IDictionary<string, ChannelInfo> channelInfos = this._repMediator.ChannelRep.Find(channelNos).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<ArticleInfo> articleInfos = articles.Select(x => x.ToDTO(channelInfos));

            return articleInfos;
        }
        #endregion

        #region # 分页获取文章列表 —— PageModel<ArticleInfo> GetArticlesByPage(string...
        /// <summary>
        /// 分页获取文章列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="channelNo">栏目编号</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="pageIndex">页索引</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>符合条件的文章记录条数</returns>
        public PageModel<ArticleInfo> GetArticlesByPage(string keywords, string channelNo, DateTime? startTime, DateTime? endTime, int pageIndex, int pageSize)
        {
            int rowCount, pageCount;

            IEnumerable<Article> articles = this._repMediator.ArticleRep.FindByPage(keywords, channelNo, startTime, endTime, pageIndex, pageSize, out rowCount, out pageCount).ToArray();

            IEnumerable<string> channelNos = articles.Select(x => x.ChannelNo);
            IDictionary<string, ChannelInfo> channelInfos = this._repMediator.ChannelRep.Find(channelNos).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<ArticleInfo> articleInfos = articles.Select(x => x.ToDTO(channelInfos));

            return new PageModel<ArticleInfo>(articleInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 根据栏目获取文章列表 —— IEnumerable<ArticleInfo> GetArticlesByChannel(...
        /// <summary>
        /// 根据栏目获取文章列表
        /// </summary>
        /// <param name="channelNo">栏目编号</param>
        /// <returns>文章列表</returns>
        public IEnumerable<ArticleInfo> GetArticlesByChannel(string channelNo)
        {
            IEnumerable<Article> articles = this._repMediator.ArticleRep.FindByChannel(channelNo).ToArray();

            IEnumerable<string> channelNos = articles.Select(x => x.ChannelNo);
            IDictionary<string, ChannelInfo> channelInfos = this._repMediator.ChannelRep.Find(channelNos).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<ArticleInfo> articleInfos = articles.Select(x => x.ToDTO(channelInfos));

            return articleInfos;
        }
        #endregion

        #region # 根据栏目与数量获取文章列表 —— IEnumerable<ArticleInfo> GetArticlesByCount(...
        /// <summary>
        /// 根据栏目与数量获取文章列表
        /// </summary>
        /// <param name="channelNo">栏目编号</param>
        /// <param name="count">数量</param>
        /// <returns>文章列表</returns>
        public IEnumerable<ArticleInfo> GetArticlesByCount(string channelNo, int count)
        {
            IEnumerable<Article> articles = this._repMediator.ArticleRep.Find(channelNo, count).ToArray();

            IEnumerable<string> channelNos = articles.Select(x => x.ChannelNo);
            IDictionary<string, ChannelInfo> channelInfos = this._repMediator.ChannelRep.Find(channelNos).ToDictionary(x => x.Key, x => x.Value.ToDTO());

            IEnumerable<ArticleInfo> articleInfos = articles.Select(x => x.ToDTO(channelInfos));

            return articleInfos;
        }
        #endregion


        #region # 获取栏目 —— ChannelInfo GetChannel(Guid channelId)
        /// <summary>
        /// 获取栏目
        /// </summary>
        /// <param name="channelId">栏目Id</param>
        /// <returns>栏目</returns>
        public ChannelInfo GetChannel(Guid channelId)
        {
            Channel currentChannel = this._repMediator.ChannelRep.Single(channelId);
            ChannelInfo currentChannelInfo = currentChannel.ToDTO();

            return currentChannelInfo;
        }
        #endregion

        #region # 获取栏目 —— ChannelInfo GetChannelByNo(string channelNo)
        /// <summary>
        /// 获取栏目
        /// </summary>
        /// <param name="channelNo">栏目编号</param>
        /// <returns>栏目</returns>
        public ChannelInfo GetChannelByNo(string channelNo)
        {
            Channel currentChannel = this._repMediator.ChannelRep.Single(channelNo);
            ChannelInfo currentChannelInfo = currentChannel.ToDTO();

            return currentChannelInfo;
        }
        #endregion

        #region # 获取栏目列表 —— IEnumerable<ChannelInfo> GetChannels(bool? isNavigator)
        /// <summary>
        /// 获取栏目列表
        /// </summary>
        /// <param name="isNavigator">是否是导航</param>
        /// <returns>栏目列表</returns>
        public IEnumerable<ChannelInfo> GetChannels(bool? isNavigator)
        {
            IEnumerable<Channel> channels = this._repMediator.ChannelRep.Find(isNavigator);
            IEnumerable<ChannelInfo> channelInfos = channels.Select(x => x.ToDTO());

            return channelInfos;
        }
        #endregion

        #region # 根据上级栏目获取栏目列表 —— IEnumerable<ChannelInfo> GetChannelsByParent(string...
        /// <summary>
        /// 根据上级栏目获取栏目列表
        /// </summary>
        /// <param name="parentChannelNo">上级栏目编号</param>
        /// <param name="isNavigator">是否是导航</param>
        /// <returns>栏目列表</returns>
        public IEnumerable<ChannelInfo> GetChannelsByParent(string parentChannelNo, bool? isNavigator)
        {
            IEnumerable<Channel> channels = this._repMediator.ChannelRep.Find(parentChannelNo, isNavigator);
            IEnumerable<ChannelInfo> channelInfos = channels.Select(x => x.ToDTO());

            return channelInfos;
        }
        #endregion

        #region # 获取栏目下文章条数/页数 —— KeyValuePair<int, int> GetArticlePageByChannel(...
        /// <summary>
        /// 获取栏目下文章条数/页数
        /// </summary>
        /// <param name="channelNo">栏目编号</param>
        /// <returns>栏目下文章条数/页数</returns>
        /// <remarks>KeyValuePair[int, int]，[条数, 页数]</remarks>
        public KeyValuePair<int, int> GetArticlePageByChannel(string channelNo)
        {
            Channel currentChannel = this._repMediator.ChannelRep.Single(channelNo);
            KeyValuePair<int, int> page = this._svcMediator.ChannelSvc.GetPage(currentChannel);

            return page;
        }
        #endregion
    }
}
